home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Basic Toolbox
/
Visual Basic Toolbox (P.I.E.)(1996).ISO
/
graphics
/
256pb2
/
dib.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-12
|
14KB
|
428 lines
//-----------------------------------------------------------------------------
// DIB.C
//
// This is a collection of useful DIB manipulation/information gathering
// functions. Many functions are supplied simply to take the burden
// of taking into account whether a DIB is a Win30 style or OS/2 style
// DIB away from the application.
//
// The functions in this module assume that the DIB pointers or handles
// passed to them point to a block of memory in one of two formats:
//
// a) BITMAPINFOHEADER + color table + DIB bits (3.0 style DIB)
// b) BITMAPCOREHEADER + color table + DIB bits (OS/2 PM style)
//
// The SDK Reference, Volume 2 describes these data structures.
//
// A number of functions in this module were lifted from SHOWDIB,
// and modified to handle OS/2 DIBs.
//
// The functions in this module could be streamlined (made faster and
// smaller) by removing the OS/2 DIB specific code, and assuming all
// DIBs passed to it are Win30 style DIBs. The DIB file reading code
// would need to be modified to always convert DIBs to Win30 style
// DIBs. The only reason this isn't done in DIBView is because DIBView
// was written to test display and printer drivers (which are supposed
// to support OS/2 DIBs wherever they support Win30 style DIBs). SHOWDIB
// is a great example of how to go about doing this.
//-----------------------------------------------------------------------------
#include <windows.h>
#include <memory.h>
#include "errors.h"
#include "dib.h"
//---------------------------------------------------------------------
//
// Function: FindDIBBits
//
// Purpose: Given a pointer to a DIB, returns a pointer to the
// DIB's bitmap bits.
//
// Parms: lpbi == pointer to DIB header (either BITMAPINFOHEADER
// or BITMAPCOREHEADER)
//
// History: Date Reason
// 6/01/91 Created
//
//---------------------------------------------------------------------
LPSTR FAR PASCAL FindDIBBits (LPSTR lpbi)
{
return (lpbi + *(LPDWORD)lpbi + PaletteSize (lpbi));
}
//---------------------------------------------------------------------
//
// Function: DIBNumColors
//
// Purpose: Given a pointer to a DIB, returns a number of colors in
// the DIB's color table.
//
// Parms: lpbi == pointer to DIB header (either BITMAPINFOHEADER
// or BITMAPCOREHEADER)
//
// History: Date Reason
// 6/01/91 Created
//
//---------------------------------------------------------------------
WORD FAR PASCAL DIBNumColors (LPSTR lpbi)
{
WORD wBitCount;
// If this is a Windows style DIB, the number of colors in the
// color table can be less than the number of bits per pixel
// allows for (i.e. lpbi->biClrUsed can be set to some value).
// If this is the case, return the appropriate value.
if (IS_WIN30_DIB (lpbi))
{
DWORD dwClrUsed;
dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed;
if (dwClrUsed)
return (WORD) dwClrUsed;
}
// Calculate the number of colors in the color table based on
// the number of bits per pixel for the DIB.
if (IS_WIN30_DIB (lpbi))
wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount;
else
wBitCount = ((LPBITMAPCOREHEADER) lpbi)->bcBitCount;
switch (wBitCount)
{
case 1:
return 2;
case 4:
return 16;
case 8:
return 256;
default:
return 0;
}
}
//---------------------------------------------------------------------
//
// Function: PaletteSize
//
// Purpose: Given a pointer to a DIB, returns number of bytes
// in the DIB's color table.
//
// Parms: lpbi == pointer to DIB header (either BITMAPINFOHEADER
// or BITMAPCOREHEADER)
//
// History: Date Reason
// 6/01/91 Created
//
//---------------------------------------------------------------------
WORD FAR PASCAL PaletteSize (LPSTR lpbi)
{
if (IS_WIN30_DIB (lpbi))
return (DIBNumColors (lpbi) * sizeof (RGBQUAD));
else
return (DIBNumColors (lpbi) * sizeof (RGBTRIPLE));
}
//---------------------------------------------------------------------
//
// Function: CreateDIBPalette
//
// Purpose: Given a handle to a DIB, constructs a logical palette,
// and returns a handle to this palette.
//
// Stolen almost verbatim from ShowDIB.
//
// Parms: hDIB == HANDLE to global memory with a DIB header
// (either BITMAPINFOHEADER or BITMAPCOREHEADER)
//
// History: Date Reason
// 6/01/91 Created
//
//---------------------------------------------------------------------
HPALETTE FAR PASCAL CreateDIBPalette (HANDLE hDIB)
{
LPLOGPALETTE lpPal;
HANDLE hLogPal;
HPALETTE hPal = NULL;
int i, wNumColors;
LPSTR lpbi;
LPBITMAPINFO lpbmi;
LPBITMAPCOREINFO lpbmc;
BOOL bWinStyleDIB;
if (!hDIB)
return NULL;
lpbi = GlobalLock (hDIB);
lpbmi = (LPBITMAPINFO) lpbi;
lpbmc = (LPBITMAPCOREINFO) lpbi;
wNumColors = DIBNumColors (lpbi);
bWinStyleDIB = IS_WIN30_DIB (lpbi);
if (wNumColors)
{
hLogPal = GlobalAlloc (GHND, sizeof (LOGPALETTE) +
sizeof (PALETTEENTRY) * wNumColors);
if (!hLogPal)
{
DIBError (ERR_CREATEPAL);
GlobalUnlock (hDIB);
return NULL;
}
lpPal = (LPLOGPALETTE) GlobalLock (hLogPal);
lpPal->palVersion = PALVERSION;
lpPal->palNumEntries = wNumColors;
for (i = 0; i < wNumColors; i++)
{
if (bWinStyleDIB)
{
lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
lpPal->palPalEntry[i].peFlags = 0;
}
else
{
lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
lpPal->palPalEntry[i].peFlags = 0;
}
}
hPal = CreatePalette (lpPal);
if (!hPal)
DIBError (ERR_CREATEPAL);
GlobalUnlock (hLogPal);
GlobalFree (hLogPal);
}
GlobalUnlock (hDIB);
return hPal;
}
//---------------------------------------------------------------------
//
// Function: DIBHeight
//
// Purpose: Given a pointer to a DIB, returns its height. Note
// that it returns a DWORD (since a Win30 DIB can have
// a DWORD in its height field), but under Win30, the
// high order word isn't used!
//
// Parms: lpDIB == pointer to DIB header (either BITMAPINFOHEADER
// or BITMAPCOREHEADER)
//
// History: Date Reason
// 6/01/91 Created
//
//---------------------------------------------------------------------
DWORD FAR PASCAL DIBHeight (LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi;
LPBITMAPCOREHEADER lpbmc;
lpbmi = (LPBITMAPINFOHEADER) lpDIB;
lpbmc = (LPBITMAPCOREHEADER) lpDIB;
if (lpbmi->biSize == sizeof (BITMAPINFOHEADER))
return lpbmi->biHeight;
else
return (DWORD) lpbmc->bcHeight;
}
//---------------------------------------------------------------------
//
// Function: DIBWidth
//
// Purpose: Given a pointer to a DIB, returns its width. Note
// that it returns a DWORD (since a Win30 DIB can have
// a DWORD in its width field), but under Win30, the
// high order word isn't used!
//
// Parms: lpDIB == pointer to DIB header (either BITMAPINFOHEADER
// or BITMAPCOREHEADER)
//
// History: Date Reason
// 6/01/91 Created
//
//---------------------------------------------------------------------
DWORD FAR PASCAL DIBWidth (LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi;
LPBITMAPCOREHEADER lpbmc;
lpbmi = (LPBITMAPINFOHEADER) lpDIB;
lpbmc = (LPBITMAPCOREHEADER) lpDIB;
if (lpbmi->biSize == sizeof (BITMAPINFOHEADER))
return lpbmi->biWidth;
else
return (DWORD) lpbmc->bcWidth;
}
//---------------------------------------------------------------------
//
// Function: DIBLoad
//
// Purpose: Given a pointer to a DIB filename, will open that file
// and read the DIB data into a globally allocated memory
// block.
//
// Parms: lpszDIBName == pointer to a string containing the name
// (any valid DOS filename) of the DIB file
//
// Returns: Will return a handle to the global memory block if
// successful. Will return NULL otherwise.
//
// History: Date Reason
// 3/10/92 Created
//
//---------------------------------------------------------------------
HANDLE FAR PASCAL DIBLoad (LPSTR lpszDIBName)
{
unsigned fh;
LPBITMAPINFOHEADER lpbi;
OFSTRUCT of;
BITMAPFILEHEADER bf;
WORD nNumColors;
WORD offBits;
HANDLE hDIBInfo = NULL;
char * szMsg;
HANDLE result = NULL; /* assume failure */
/* Open the file and get a handle to it's BITMAPINFO */
hDIBInfo = GlobalAlloc(GMEM_MOVEABLE,
(DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
if (hDIBInfo == NULL) {
wsprintf((LPSTR) szMsg, "Not enough memory to load '%s'", lpszDIBName);
MessageBox((HWND) NULL, (LPSTR) szMsg, "Error", MB_ICONSTOP | MB_OK);
return (NULL);
}
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIBInfo);
fh = OpenFile (lpszDIBName, &of, OF_READ);
if (fh == -1) {
wsprintf((LPSTR) szMsg, "Can't open file '%s'", lpszDIBName);
MessageBox((HWND) NULL, (LPSTR) szMsg, "Error", MB_ICONSTOP | MB_OK);
return (NULL);
}
/* read the BITMAPFILEHEADER */
if (sizeof (bf) != _lread (fh, (LPSTR)&bf, sizeof (bf)))
goto ErrExit;
if (bf.bfType != 0x4d42) /* 'BM' */
goto ErrExit;
if (sizeof(BITMAPINFOHEADER) != _lread (fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
goto ErrExit;
/* don't even deal with OS/2 bitmaps */
if (!IS_WIN30_DIB(lpbi)) {
wsprintf((LPSTR) szMsg, "OS/2 bitmaps (%s) not supported!", lpszDIBName);
MessageBox((HWND) NULL, (LPSTR) szMsg, "Error", MB_ICONSTOP | MB_OK);
goto ErrExit;
}
if (!(nNumColors = (WORD)lpbi->biClrUsed))
{
/* no color table for 24-bit, default size otherwise */
if (lpbi->biBitCount != 24)
nNumColors = 1 << lpbi->biBitCount; /* standard size table */
}
/* fill in some default values if they are zero */
if (lpbi->biClrUsed == 0)
lpbi->biClrUsed = (DWORD)nNumColors;
if (lpbi->biSizeImage == 0)
{
lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
* lpbi->biHeight;
}
/* get a proper-sized buffer for header, color table and bits */
GlobalUnlock(hDIBInfo);
hDIBInfo = GlobalReAlloc(hDIBInfo, lpbi->biSize +
nNumColors * sizeof(RGBQUAD) +
lpbi->biSizeImage, 0);
if (!hDIBInfo) { /* can't resize buffer for loading */
wsprintf((LPSTR) szMsg, "Not enough memory to load '%s'", lpszDIBName);
MessageBox((HWND) NULL, (LPSTR) szMsg, "Error", MB_ICONSTOP | MB_OK);
goto ErrExit;
}
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIBInfo);
/* read the color table */
_lread (fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
/* offset to the bits from start of DIB header */
offBits = (WORD)lpbi->biSize + nNumColors * sizeof(RGBQUAD);
if (bf.bfOffBits != 0L)
{
_llseek(fh,bf.bfOffBits, SEEK_SET);
}
if (lpbi->biSizeImage == lread(fh, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
result = hDIBInfo;
ErrExit:
_lclose(fh);
GlobalUnlock(hDIBInfo);
return(result);
}
/**************** PRIVATE ROUTINE TO READ MORE THAN 64K *********************/
/****************************************************************************
* *
* FUNCTION : lread(int fh, VOID FAR *pv, DWORD ul) *
* *
* PURPOSE : Reads data in steps of 32k till all the data has been read.*
* *
* RETURNS : 0 - If read did not proceed correctly. *
* number of bytes read otherwise. *
* *
****************************************************************************/
DWORD PASCAL lread (int fh, VOID far *pv, DWORD ul)
{
DWORD ulT = ul;
BYTE huge *hp = pv;
while (ul > (DWORD)MAXREAD) {
if (_lread(fh, (LPSTR)hp, (WORD)MAXREAD) != MAXREAD)
return 0;
ul -= MAXREAD;
hp += MAXREAD;
}
if (_lread(fh, (LPSTR)hp, (WORD)ul) != (WORD)ul)
return 0;
return ulT;
}